package com.gitee.wsl.android.ui.signature.pan

import com.gitee.wsl.common.ui.base.ControlPoint


/**
 * 贝塞尔操作工具类，对点的位置和宽度控制的bezier曲线，主要是两个点，都包含了宽度和点的坐标
 *
 * @since 2018/06/15
 * @author king
 */
class Bezier {
    /**
     * 控制点
     */
    private val mControl = ControlPoint()

    /**
     * 距离
     */
    private val mDestination = ControlPoint()

    /**
     * 下一个需要控制点
     */
    private val mNextControl = ControlPoint()

    /**
     * 资源的点
     */
    private val mSource = ControlPoint()

    /**
     * 初始化两个点，
     *
     * @param last 最后的点的信息
     * @param cur  当前点的信息,当前点的信息，当前点的是根据事件获得，同时这个当前点的宽度是经过计算的得出的
     */
    fun init(last: ControlPoint, cur: ControlPoint) {
        init(last.x, last.y, last.width, cur.x, cur.y, cur.width)
    }

    fun init(lastx: Float, lasty: Float, lastWidth: Float, x: Float, y: Float, width: Float) {
        //资源点设置，最后的点的为资源点
        mSource[lastx, lasty] = lastWidth
        val xmid = getMid(lastx, x)
        val ymid = getMid(lasty, y)
        val wmid = getMid(lastWidth, width)
        //距离点为平均点
        mDestination[xmid, ymid] = wmid
        //控制点为当前的距离点
        mControl[getMid(lastx, xmid), getMid(lasty, ymid)] = getMid(lastWidth, wmid)
        //下个控制点为当前点
        mNextControl[x, y] = width
    }

    fun addNode(cur: ControlPoint) {
        addNode(cur.x, cur.y, cur.width)
    }

    /**
     * 替换就的点，原来的距离点变换为资源点，控制点变为原来的下一个控制点，距离点取原来控制点的和新的的一半
     * 下个控制点为新的点
     *
     * @param x     新的点的坐标
     * @param y     新的点的坐标
     * @param width
     */
    fun addNode(x: Float, y: Float, width: Float) {
        mSource.set(mDestination)
        mControl.set(mNextControl)
        mDestination[getMid(mNextControl.x, x), getMid(mNextControl.y, y)] =
            getMid(mNextControl.width, width)
        mNextControl[x, y] = width
    }

    /**
     * 结合手指抬起来的动作，告诉现在的曲线控制点也必须变化，其实在这里也不需要结合着up事件使用
     * 因为在down的事件中，所有点都会被重置，然后设置这个没有多少意义，但是可以改变下个事件的朝向改变
     * 先留着，因为后面如果需要控制整个颜色的改变的话，我的依靠这个方法，还有按压的时间的变化
     */
    fun end() {
        mSource.set(mDestination)
        val x = getMid(mNextControl.x, mSource.x)
        val y = getMid(mNextControl.y, mSource.y)
        val w = getMid(mNextControl.width, mSource.width)
        mControl[x, y] = w
        mDestination.set(mNextControl)
    }

    /**
     * 获取点信息
     */
    fun getPoint(t: Float): ControlPoint {
        val x = getX(t)
        val y = getY(t)
        val w = getW(t)
        val point = ControlPoint()
        point[x, y] = w
        return point
    }

    /**
     * 三阶曲线的控制点
     */
    private fun getValue(p0: Float, p1: Float, p2: Float, t: Float): Float {
        val a = p2 - 2 * p1 + p0
        val b = 2 * (p1 - p0)
        return a * t * t + b * t + p0
    }

    private fun getX(t: Float): Float {
        return getValue(mSource.x, mControl.x, mDestination.x, t)
    }

    private fun getY(t: Float): Float {
        return getValue(mSource.y, mControl.y, mDestination.y, t)
    }

    private fun getW(t: Float): Float {
        return getWidth(mSource.width, mDestination.width, t)
    }

    /**
     * 获取两个数平均值
     *
     * @param x1 一个点的x
     * @param x2 一个点的x
     */
    private fun getMid(x1: Float, x2: Float): Float {
        return ((x1 + x2) / 2.0f)
    }

    private fun getWidth(w0: Float, w1: Float, t: Float): Float {
        return w0 + (w1 - w0) * t
    }
}
